package com.thghh.bcode;


import javassist.*;
import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.BooleanMemberValue;
import javassist.bytecode.annotation.IntegerMemberValue;
import javassist.bytecode.annotation.StringMemberValue;

import java.io.IOException;

/**
 * @author Zhikang.Peng
 * @version 1.0
 * @email thghh@qq.com
 * @date 2020/11/26 16:05
 */
public class GenerateByteCode {

    private ClassPool classPool;
    private CtClass clazz;
    private ClassFile classFile;

    public GenerateByteCode(String className) {
        classPool = ClassPool.getDefault();
        clazz = new ForwardingCtClass(classPool.makeClass(className));
        classFile = clazz.getClassFile();
    }

    public byte[] generateByteCode() throws NotFoundException, CannotCompileException, IOException {
        // 类上添加注解
        classFile.setAccessFlags(AccessFlag.PUBLIC);
        ConstPool cp = classFile.getConstPool();

        AnnotationsAttribute classAnnotation = new AnnotationsAttribute(cp, AnnotationsAttribute.invisibleTag);
        Annotation lombokData = new Annotation("lombok.Data", cp);
        classAnnotation.addAnnotation(lombokData);
        Annotation noArgsConstructor = new Annotation("lombok.NoArgsConstructor", cp);
        classAnnotation.addAnnotation(noArgsConstructor);
        Annotation equalsAndHashCode = new Annotation("lombok.EqualsAndHashCode", cp);
        equalsAndHashCode.addMemberValue("callSuper", new BooleanMemberValue(false, cp));
        classAnnotation.addAnnotation(equalsAndHashCode);
        classFile.addAttribute(classAnnotation);
        classFile.setSuperclass("com.thghh.bcode.model.Property");
        // 增加字段
        CtClass stringClazz = classPool.get("java.lang.String");
        CtField field = new CtField(stringClazz, "name", clazz);
        field.setModifiers(Modifier.PRIVATE);
        FieldInfo fieldInfo = field.getFieldInfo();
        // 属性附上注解
        AnnotationsAttribute fieldAttr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
        Annotation beanColumnClass = new Annotation("com.thghh.table.BeanColumn", cp);
        beanColumnClass.addMemberValue("name", new StringMemberValue("name", cp));
        beanColumnClass.addMemberValue("index", new IntegerMemberValue(cp, 10));

        fieldAttr.addAnnotation(beanColumnClass);
        fieldInfo.addAttribute(fieldAttr);
        clazz.addField(field);
        return clazz.toBytecode();
    }

    public String getClassName() {
        return classFile.getName();
    }

    public Class<?> toClass() throws CannotCompileException {
        return clazz.toClass();
    }
}
